#include "CTestReport.h"
#include "CtrlRadarChart.h"
#include "GenOpt.h"
#include <QChart>
#include <QFile>
#include <QLineSeries>
#include <QTextStream>
#include <QValueAxis>
#include <QXYSeries>
#include <qabstractaxis.h>
#include <qchart.h>
#include <qchartview.h>
#include <qimage.h>
#include <qpainter.h>
#include <qscatterseries.h>

CTestReport::CTestReport() {}

CTestReport::~CTestReport() {}

int CTestReport::ClearAll() {
  result_info_.clear();
  return 0;
}

int CTestReport::GetMarkInfo(QString file, QVector<EventInfo_t> &info) {
  QString file_name = CGenOpt::GetFileNameFromPath(file);
  int index = file_name.indexOf("[");
  while (index != -1) {
    EventInfo_t event_info_in = {0};
    EventInfo_t event_info_out = {0};
    /*找到第一个不是[的字符，防止标定数据有的是一个[，有的是两个[*/
    while (index < file_name.length() && file_name[index] == '[') {
      index++;
    }

    int start = file_name.indexOf("_", index + 1);
    if (start == -1) {
      continue;
    }
    QString strIdIn = file_name.mid(index, start - index);
    event_info_in.id = strIdIn.toUInt();
    int mid = file_name.indexOf("_", start + 1);
    if (mid == -1) {
      continue;
    }
    event_info_in.plate_num = file_name.mid(start + 1, mid - start - 1);
    event_info_in.type = 0;
    info.append(event_info_in);
    int end = file_name.indexOf("]", mid + 1);
    if (end == -1) {
      continue;
    }
    QString strIdOut = file_name.mid(mid + 1, end - mid - 1);
    event_info_out.id = strIdOut.toUInt();
    event_info_out.plate_num = event_info_in.plate_num;
    event_info_out.type = 1;
    info.append(event_info_out);
    index = file_name.indexOf("[", index + 1);
  }
  return 0;
}

int CTestReport::WriteMarkInfoToAlgResult(AlgResultTestInfo_t *info,
                                          QVector<EventInfo_t> mark) {
  for (const auto &event : mark) {
    if (event.type == 0) {
      info->mark_in_cnt++;
    } else {
      info->mark_out_cnt++;
    }
  }
  return 0;
}

int CTestReport::WriteAlgInfoToAlgResult(AlgResultTestInfo_t *info,
                                         QVector<EventInfo_t> alg) {
  for (const auto &event : alg) {
    if (event.type == 0) {
      info->trig_in_cnt++;
    } else {
      info->trig_out_cnt++;
    }
  }
  return 0;
}

int CTestReport::WriteTestResult(AlgResultTestInfo_t *info,
                                 QVector<EventInfo_t> mark,
                                 QVector<EventInfo_t> resl) {
  uint32_t in_diff_sum = 0;
  uint32_t in_diff_cnt = 0;
  uint32_t out_diff_cnt = 0;
  uint32_t out_diff_sum = 0;
  uint32_t id = 0;
  uint32_t offset = 0;
  bool found_trig = false;

  for (int i = 0; i < mark.size(); i++) {
    EventInfo_t mark_event = mark.at(i);
    EventInfo_t mark_event_next;
    bool found_trig = false;
    if (mark_event.type == 0) {
      /*入场事件*/
      for (const auto &resl_event : resl) {
        if (resl_event.type != 0) {
          continue;
        }
        int32_t diff_value = (int32_t)resl_event.id - (int32_t)mark_event.id;
        if (i != mark.size() - 1) {
          mark_event_next = mark.at(i + 1);
        } else {
          mark_event_next = mark_event;
        }
        if ((abs(diff_value) < 16) || ((resl_event.id > mark_event.id) &&
                                       (resl_event.id < mark_event_next.id))) {
          offset = (resl_event.id > mark_event.id)
                       ? (resl_event.id - mark_event.id)
                       : 0;
          if (offset > 10) {
            info->late_trig_in_cnt++;
          }
          in_diff_sum += offset;
          in_diff_cnt++;
          found_trig = true;
          break;
        }
      }
      if (!found_trig) {
        info->miss_trig_cnt++;
      }
    } else {
      /*出场事件*/
      for (const auto &resl_event : resl) {
        if (resl_event.type != 1) {
          continue;
        }
        int32_t diff_value = (int32_t)resl_event.id - (int32_t)mark_event.id;
        if (((diff_value < 24) && (diff_value >= 0)) ||
            ((diff_value < 0) && (diff_value > -64))) {
          offset = (resl_event.id > mark_event.id)
                       ? (resl_event.id - mark_event.id)
                       : 0;
          if (offset > 10) {
            info->late_trig_out_cnt++;
          }
          out_diff_sum += offset;
          out_diff_cnt++;
          found_trig = true;
          break;
        }
      }
      if (!found_trig) {
        info->miss_trig_cnt++;
      }
    }
  }
  info->trig_in_diff = in_diff_cnt == 0 ? 0 : in_diff_sum / in_diff_cnt;
  info->trig_out_diff = out_diff_cnt == 0 ? 0 : out_diff_sum / out_diff_cnt;
  info->false_trig_cnt = resl.size() - (mark.size() - info->miss_trig_cnt);
  return 0;
}

int CTestReport::AddTestResult(QString file, QVector<EventInfo_t> &resl) {
  QVector<EventInfo_t> mark;
  AlgResultTestInfo_t info = {0};
  /*获得标记信息*/
  info.file = file;
  GetMarkInfo(file, mark);
  WriteMarkInfoToAlgResult(&info, mark);
  WriteAlgInfoToAlgResult(&info, resl);
  WriteTestResult(&info, mark, resl);
  result_info_.append(info);
  return 0;
}

QString CTestReport::MakeTableHead() {
  return QString(
      ", 测试文件, 标记入场事件数量, 标记出场事件数量, 入场事件触发次数, "
      "出场事件触发次数, "
      "入场触发平均延迟, 出场触发平均延迟, 漏触发, 误触发, "
      "入场触发不及时事件, "
      "出场触发不及时事件,触发率, 误触法率, 平均触发延迟, "
      "触发不及时率\n");
}

QString CTestReport::MakeTableContent(AlgResultTestInfo_t *resul_sum) {
  QString table_content;
  for (const auto &info : result_info_) {
    table_content += QString(", %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11\n")
                         .arg(info.file)
                         .arg(info.mark_in_cnt)
                         .arg(info.mark_out_cnt)
                         .arg(info.trig_in_cnt)
                         .arg(info.trig_out_cnt)
                         .arg(info.trig_in_diff)
                         .arg(info.trig_out_diff)
                         .arg(info.miss_trig_cnt)
                         .arg(info.false_trig_cnt)
                         .arg(info.late_trig_in_cnt)
                         .arg(info.late_trig_out_cnt);
    resul_sum->mark_in_cnt += info.mark_in_cnt;
    resul_sum->mark_out_cnt += info.mark_out_cnt;
    resul_sum->trig_in_cnt += info.trig_in_cnt;
    resul_sum->trig_out_cnt += info.trig_out_cnt;
    resul_sum->trig_in_diff += info.trig_in_diff;
    resul_sum->trig_out_diff += info.trig_out_diff;
    resul_sum->miss_trig_cnt += info.miss_trig_cnt;
    resul_sum->false_trig_cnt += info.false_trig_cnt;
    resul_sum->late_trig_in_cnt += info.late_trig_in_cnt;
    resul_sum->late_trig_out_cnt += info.late_trig_out_cnt;
  }
  return table_content;
}

QString CTestReport::MakeTableTotal(AlgResultTestInfo_t *resul_sum) {
  QString table_total;
  table_total =
      QString("总计, %1, %2, %3, %4, %5, %6, %7, %8, %9, %10, %11, %12%, %13%, "
              "%14, "
              "%15%\n")
          .arg(result_info_.size())
          .arg(resul_sum->mark_in_cnt)
          .arg(resul_sum->mark_out_cnt)
          .arg(resul_sum->trig_in_cnt)
          .arg(resul_sum->trig_out_cnt)
          .arg(resul_sum->trig_in_diff)
          .arg(resul_sum->trig_out_diff)
          .arg(resul_sum->miss_trig_cnt)
          .arg(resul_sum->false_trig_cnt)
          .arg(resul_sum->late_trig_in_cnt)
          .arg(resul_sum->late_trig_out_cnt)
          .arg(100 *
               (double)(resul_sum->mark_in_cnt + resul_sum->mark_out_cnt -
                resul_sum->miss_trig_cnt) /
               (double)(resul_sum->mark_in_cnt + resul_sum->mark_out_cnt))
          .arg(100 * (double)resul_sum->false_trig_cnt /
               (double)(resul_sum->trig_in_cnt + resul_sum->trig_out_cnt))
          .arg((resul_sum->trig_in_diff + resul_sum->trig_out_diff) /
               (resul_sum->mark_in_cnt + resul_sum->mark_out_cnt -
                resul_sum->miss_trig_cnt))
          .arg(100 *
               (double)(resul_sum->late_trig_in_cnt + resul_sum->late_trig_out_cnt) /
               (double)(resul_sum->mark_in_cnt + resul_sum->mark_out_cnt));
  return table_total;
}

int CTestReport::MakeReport(QString file_name) {
  QFile file(file_name);
  if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
    return -1;
  }
  QTextStream out(&file);
  /*算法结果求和*/
  AlgResultTestInfo_t resul_sum = {0};
  out << MakeTableHead();
  out << MakeTableContent(&resul_sum);
  out << MakeTableTotal(&resul_sum);
  file.close();
  return 0;
}

int CTestReport::MakeChart(QString file_chart, QVector<uint32_t> &radar_data,
                           QVector<EventInfo_t> &mark,
                           QVector<EventInfo_t> &resl) {
  CtrlRadarChart chart;
  QVector<uint32_t> radar_dist;
  for (const auto radar : radar_data) {
    radar_dist.append((radar >> 16) & 0xFFFF);
  }
  chart.UpdateRadarData(radar_dist);
  QVector<QPoint> mark_point_in;
  QVector<QPoint> mark_point_out;
  for (const auto &event : mark) {
    if (event.type == 0) {
      mark_point_in.append(QPoint(event.id, radar_dist.at(event.id)));
    } else {
      mark_point_out.append(QPoint(event.id, radar_dist.at(event.id)));
    }
  }
  chart.MarkPoint("标记入场位置", mark_point_in, Qt::red, 15,
                  QScatterSeries::MarkerShapeStar);
  chart.MarkPoint("标记出场位置", mark_point_out, Qt::red, 15,
                  QScatterSeries::MarkerShapeCircle);

  mark_point_in.clear();
  mark_point_out.clear();
  for (const auto &event : resl) {
    if (event.type == 0) {
      mark_point_in.append(QPoint(event.id, radar_dist.at(event.id)));
    } else {
      mark_point_out.append(QPoint(event.id, radar_dist.at(event.id)));
    }
  }
  chart.MarkPoint("触发入场位置", mark_point_in, Qt::green, 20,
                  QScatterSeries::MarkerShapeStar);
  chart.MarkPoint("触发出场位置", mark_point_out, Qt::green, 10,
                  QScatterSeries::MarkerShapeCircle);
  chart.resize(1920, 540);
  chart.grab().save(file_chart);
  return 0;
}
